package com.theory.builder;


import com.theory.config.Configuration;
import com.theory.config.Environment;
import com.theory.enums.EnvironmentEnum;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;

/**
 * @author : theory
 * EMAIL   : theory@whu.edu.cn
 * TIME    : 2021/2/7
 */
public class XmlConfigBuilder extends BaseConfigBuilder {

    Element root;

    public XmlConfigBuilder(InputStream inputStream) {
        super(new Configuration());
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(inputStream);
            root = document.getRootElement();
        } catch (DocumentException e) {
            throw new RuntimeException("dom4j read the xml error, Cause: " + e);
        }
    }


    public Configuration parse() {
        //resolve <configuration>
        parseConfiguration(root);
        return configuration;
    }

    /**
     * parse the <configuration>
     *
     * @param root the root node of xml
     */
    private void parseConfiguration(Element root) {
        if (!"configuration".equals(root.getName()))
            throw new RuntimeException("the root's name doesn't equals 'configuration' ");
        environmentElement(root.element("environment"));
        mapperElement(root.element("mappers"));
    }

    /**
     * parse the <environment>
     *
     * @param element
     */
    private void environmentElement(Element element) {
        if (element == null)
            throw new RuntimeException("<element> can not be null");
        else if (!"environment".equals(element.getName())) {
            throw new RuntimeException("the element's name doesn't equals 'environment'");
        }
        //loop the properties
        Environment environment = new Environment();
        for (Object property : element.elements("property")) {
            Element propertyNode = (Element) property;
            String name = propertyNode.attributeValue("name");
            String value = propertyNode.hasContent() ? propertyNode.getText() : propertyNode.attributeValue("value");
            try {
                switch (EnvironmentEnum.valueOf(name.toUpperCase())) {
                    case URL:
                        environment.setUrl(value);
                        break;
                    case USERNAME:
                        environment.setUsername(value);
                        break;
                    case PASSWORD:
                        environment.setPassword(value);
                        break;
                    case DRIVER:
                        environment.setDriver(value);
                        break;
                }
            } catch (IllegalArgumentException e) {
                throw new IllegalArgumentException("error environment property name: " + name);
            }

        }
        configuration.setEnvironment(environment);
    }

    /**
     * parse the <mappers></mappers>
     *
     * @param mappers
     */
    private void mapperElement(Element mappers) {
        if (mappers == null)
            throw new RuntimeException("<element> can not be null");
        else if (!"mappers".equals(mappers.getName())) {
            throw new RuntimeException("the element's name doesn't equals 'mappers'");
        }
        for (Object property : mappers.elements("mapper")) {
            Element mapperNode = (Element) property;
            String resource = mapperNode.attributeValue("resource");
            InputStream inputStream = XmlConfigBuilder.class.getClassLoader().getResourceAsStream(resource);
            // read the mapper.xml and bind the interface
            XmlMapperBuilder xmlMapperBuilder = new XmlMapperBuilder(inputStream, configuration, resource);
            xmlMapperBuilder.parse();
        }
    }
}
